package ae.pcfc.cldos.online.web.util;

import java.net.ConnectException;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.jboss.resource.JBossResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.ws.client.WebServiceIOException;
import org.springframework.ws.soap.client.SoapFaultClientException;

import ae.pcfc.cldos.online.common.exception.SytemException;
import ae.pcfc.cldos.online.web.ViewUtils;

@Aspect
public class UtilityInterceptor {
	private static Logger log = null;
	
	@SuppressWarnings("rawtypes")
	private Set<Class> criticalExceptions = new HashSet<Class>(
			Arrays.asList(new Class[]{WebServiceIOException.class, JBossResourceException.class,
					ConnectException.class, SQLException.class, UnknownHostException.class, 
					SoapFaultClientException.class }));
	
	public UtilityInterceptor() {
	}

	/**
	 * A join point is in the web layer if the method is defined in a type in
	 * the ae.pcfc.cldos.online.web package or any sub-package under that.
	 */
	@Pointcut("within(ae.pcfc.cldos.online.web..*)")
	public void inWebLayer() {
	}

	@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
	public void webControllerRequestMapper() {
	}
	
	@Pointcut("args(..,errors)")
	public void webControllerBindingResult(BindingResult errors) {
	}

	@Around("inWebLayer() && webControllerRequestMapper() && webControllerBindingResult(errors)")
	public Object handleException(ProceedingJoinPoint pjp, BindingResult errors)
			throws Throwable {
		log = LoggerFactory.getLogger(pjp.getTarget().getClass());
		Object targetPage = ViewUtils.DEFAULT_VIEW;
		try {
			targetPage = pjp.proceed();
		} catch (SytemException exception) {
			log.error("AOP handler Caught Exception : ",exception);
			ViewUtils.addExceptionError(exception, errors);
		}
		System.out.println("returning == "+targetPage);
		return targetPage;

	}

	@AfterThrowing(pointcut = "inWebLayer()", throwing = "ex")
	public void logException(JoinPoint joinPoint, Exception ex) {
		log = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
		log.error("Error", ex);
		Class<? extends Exception> exceptionRuntimeClass = ex.getClass();
		if(criticalExceptions.contains(exceptionRuntimeClass)){
			org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(exceptionRuntimeClass);
			logger.fatal("Critical error", ex);
		}
	}

	@Before("inWebLayer()")
	public void logBeforeInfo(JoinPoint joinPoint) throws Throwable {

		log = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
		
		if (log.isInfoEnabled()) {
			Signature sig = joinPoint.getSignature();

//			Object[] args = joinPoint.getArgs();
//			String[] names = ((CodeSignature) sig).getParameterNames();
//			Class<?>[] types = ((CodeSignature) sig).getParameterTypes();
			StringBuffer logMessageStringBuffer = new StringBuffer();

//			for (int i = 0; i < args.length; i++) {
//				logMessageStringBuffer.append("[Name=" + names[i] + " , Type="
//						+ types[i].getName() + " , Value= " + args[i] + "]");
//
//			}
			log.info("Entering method: {} , Argument values: {}",
					sig.getName(), logMessageStringBuffer.toString());
		}
		

	}

	@AfterReturning("inWebLayer()")
	public void logAfterInfo(JoinPoint joinPoint) throws Throwable {

		if (log.isInfoEnabled()) {
			log = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
			Signature sig = joinPoint.getSignature();
			log.info("Successfuly Leaving method: {} ", sig.getName());
		}

	}
	
//	public static void criticalException(){
//		for(int i=0; i<=100; i++){
//			System.out.println("*********************************************CRITICAL EXCEPTION******************");
//		}
//	}

}
